|
Technote 1120Opening Resource Files Twice Considered Hard?By Quinn “The Eskimo!” |
CONTENTSDescribing the Problem |
Most Mac OS
programmers do not consider This Note describes the exact
behavior of All Mac OS programmers who use the Resource Manager should read the Summary section of this Note, just to familiarize themselves with the problem. In addition, programmers who are writing non-application code should carefully read the entire Note to ensure maximum compatibility for their code. |
Describing the ProblemInside
Macintosh: More Macintosh Toolbox (p1-60) has the
following to say about the behavior of
This statement is mostly true, but it certainly is not the whole truth. The exact situation is a lot more complex. Complicating FactorsThe complicating factors when opening a resource file include:
These complicating factors combine to make opening a resource file potentially much more complicated than it seems on first examination. Simplifying the ProblemFortunately, not all of the above factors actually complicate the problem. We can simplify the analysis by noting the following:
These points combine to make it much easier to describe the exact situation. What remains is to describe the behavior in each of the remaining cases. |
FSpOpenResFile Explained!The following table show the exact behavior of
The first column gives the permission value used the
first time the file was opened. The second column gives the
permission value for this call to
Each cell is labeled with a pair of items:
Gotchas and ObservationsThere are a number of important observations to be made about the above table:
fsCurPerm and Multiple User SupportMac OS 9.0 introduced the ability to host multiple users on one computer. This includes the ability to create a “Limited” user, who cannot modify files outside of their user folder. This feature causes a significant change in behavior when
you open resource files using The solution is to follow the guidelines described in the Cookbook section of this technote. All-in-all, multiple user support has not changed the nature of this problem, it has just made it more common, especially for files within the System Folder. One Final GotchaThe last problem with opening the same resource file twice is intrinsic to the design of the Resource Manager and very hard to guard against. When you open a resource file, the Resource Manager loads a catalog of all the resources (the resource map) into your heap, and uses that map to locate the data for each resource in the resource file. When changing the resource map, the Resource Manager does not coordinate between the various processes that might have the resource file open. While the Resource Manager prevents you from opening two read/write resource file reference numbers to the same resource file, it does not stop you from having a read-only and a read/write resource file reference number simultaneously. This can cause serious problems in the following situation:
The restriction is described quite well in the Special Considerations section of the description of FSpOpenResFile in Inside Macintosh: More Macintosh Toolbox, but that description is worth reiterating while we’re on the subject of opening resource files twice. |
Cookbook SolutionsThis section describes some useful techniques you can
employ to ensure that the weirdnesses of
Open Resource Files OnceIf you’re writing normal application-level code, it is easy to remember whether your process has already opened a resource file and avoid opening it twice. The following snippet shows a simple example of this.
Extending this technique for more than one resource file is left as an exercise to the developer. Open Resource Files Read OnlyIn situations where you don’t know whether a resource file has already been opened by the current process (in system extension code, for example), the easiest approach is to always open the resource file read-only. If you do this, you will always get a new resource reference number that you can safely close. A further refinement of this solution is to open, read, and close the resource file quickly, without yielding time to other processes in between. This helps prevent another process from modifying the file while you’re reading it, and minimizes your vulnerability to the trickiest gotcha described above. This refinement is only useful in certain situations, but is definitely one to keep in your “cookbook.” Check TopMapHndlIn situations where you don’t know whether a resource
file has already been opened by the current process and you
must open the resource file read/write, the best technique
is to monitor the
The following snippet illustrates the
It is important to remember that this technique is only necessary if you need to open the file read/write and you don’t know whether the file is already open by the current process. As such, this technique is needed most by non-application code—such as system extensions, shared libraries, application plug-ins—but it may also be useful for application code is running in strange environments, such as a Standard File filter function. Always Preserve CurResFileRegardless of which of above techniques you use, it is
always a good idea to bracket your calls to
Check PermissionsIf you need to write to a resource file and you are not sure whether that file has already been opened, it pays to examine the resource file reference number to ensure that it supports read/write access. While having a read/write resource file reference number is not a guarantee that writing to the file will succeed, it is a good idea to check this as the first step. You can check whether a resource file reference number is
read/write by calling the File Manager routine
|
SummaryIf you open the same resource file twice, you are vulnerable to a number of strange behaviors of the Resource Manager, including:
The best way to guard against these problems is to avoid opening a resource file twice. If this is unavoidable, this Note suggests a number of approaches you can use to minimize your vulnerability. |
Change History
|
Thanks to Brian Bechtel, Pete Gontier, Jim Luther, and Scott Marcy.